package com.tyfspring.aop.framework.autoproxy;

import com.tyfspring.aop.*;
import com.tyfspring.aop.aspectj.AspectJExpressionPointcut;
import com.tyfspring.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.tyfspring.aop.framework.ProxyFactory;
import com.tyfspring.beans.aware.BeanFactoryAware;
import com.tyfspring.beans.config.InstantiationAwareBeanPostProcessor;
import com.tyfspring.beans.config.PropertyValues;
import com.tyfspring.beans.exception.BeansException;
import com.tyfspring.beans.factory.BeanFactory;
import com.tyfspring.beans.factory.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;

import java.util.Collection;

/**
 * @Description TODO
 * @Author shallow
 * @Date 2023/4/18 16:34
 */

public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (isInfrastructureClass(beanClass)) return null;
        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointCut().getClassFilter();
            if (!classFilter.matches(beanClass)){
                //当前bean不是目标对象，看下一个advisor
                continue;
            }
            AdvisedSupport advisedSupport = new AdvisedSupport();
            TargetSource targetSource = null;
            try{
                targetSource = new TargetSource(beanClass.getDeclaredConstructor().newInstance());
            }catch (Exception e){
                e.printStackTrace();
            }
            advisedSupport.setTargetSource(targetSource);
            //MethodInterceptor是Advice的子接口，向下转型
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
            advisedSupport.setMethodMatcher(advisor.getPointCut().getMethodMatcher());
            advisedSupport.setProxyTargetClass(false);
            return new ProxyFactory(advisedSupport).getProxy();

        }
        return null;
    }

    private boolean isInfrastructureClass(Class<?> beanClass) {
        //确定此Class对象表示的类或接口是否与指定参数表示的类或接口相同，或者是该Class类或接口的超类或超接口。
        //看该对象是否是aop的一部分，如果是则不进行增强
        return Advice.class.isAssignableFrom(beanClass)|| Pointcut.class.isAssignableFrom(beanClass)||Advisor.class.isAssignableFrom(beanClass);
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return false;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        return null;
    }
}
